import { nextTick, ref, watch, type Ref } from 'vue'

export interface WSResult {
  /**
   * 消息类型编号
   */
  messageType: string

  /**
   * 数据（JSON字符串）
   */
  data?: any
}
function objectToParam(obj: { [key: string]: any }): string {
  const paramStr = Object.keys(obj)
    .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
    .join('&')
  return '?' + paramStr
}
export default function webSocketWrapper(url: string, params: { [key: string]: any }) {
  const listenerMap: { [key: string]: ((data: any) => void)[] } = {}
  const isConnected = ref(false)
  const stateAssociation = ref<boolean | null>(true)

  let putTask: { path: string; message: any }[] = []
  watch(
    () => stateAssociation.value,
    (newVal) => {
      if (newVal === true) {
        if (!isConnected.value) connect()
      } else if (newVal === false) {
        if (isConnected.value) close()
      }
    }
  )

  function connect() {
    if (isConnected.value || !stateAssociation.value) return
    try {
      uni.connectSocket({
        url: import.meta.env.VITE_APP_WS_BASE_API + url + objectToParam(params)
      })
    } catch (e) {
      console.log('连接失败')
    }
  }
  function reconnection() {
    setTimeout(() => connect(), 3000)
  }

  function close(callback?: () => void) {
    uni.closeSocket({
      success: () => {
        if (callback != null) callback()
      }
    })
  }
  connect() // 首次连接
  uni.onSocketOpen(function (res) {
    console.log('WebSocket连接已打开！')
    isConnected.value = true
    // 处理未处理putTak
    if (putTask.length > 0) {
      // 从最早push的开始
      ;[...putTask].reverse().forEach((task) => {
        uni.sendSocketMessage({
          data: JSON.stringify(task)
        })
      })
      putTask = []
    }
  })

  uni.onSocketClose(function (res) {
    console.log('WebSocket 已关闭！')
    isConnected.value = false
    reconnection()
  })
  uni.onSocketError(function (res) {
    console.log('WebSocket连接打开失败，请检查！')
    isConnected.value = false
    reconnection()
  })
  uni.onSocketMessage(function (res) {
    console.log('收到服务器内容：' + res.data)
    const result: WSResult = JSON.parse(res.data)
    if (result.messageType == null) {
      throw new Error('消息无法调度')
    }
    listenerMap[result.messageType]?.forEach((listener) => listener(result.data))
  })
  function put(subPath: string, data?: any) {
    if (!isConnected.value && stateAssociation.value !== false) {
      // 当没有连接时，放到队列中，等连接时再发送
      putTask.push({ path: subPath, message: data })
      return
    }
    uni.sendSocketMessage({
      data: JSON.stringify({ path: subPath, message: data })
    })
  }
  function createListener(subPath: string) {
    let listeners = listenerMap[subPath]
    if (listeners == null) listeners = listenerMap[subPath] = []
    return {
      onListener(callback: (data: any) => void) {
        listeners.push(callback)
        return () => {
          const index = listeners.indexOf(callback)
          if (index >= 0) listeners.splice(index, 1)
        }
      }
    }
  }

  return { put, createListener, isConnected, connect, close, stateAssociation }
}
